package dk.eclipse.android.badassapp.distance;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.AsyncTask;
import android.view.Gravity;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;

import dk.eclipse.android.badassapp.distance.HttpGeoCoder.AddressFoundCallback;
import dk.eclipse.android.badassapp.distance.HttpGeoCoder.MyAddress;
import dk.eclipse.android.badassapp.helper.MyHelper;

/**
 * @author jaw Puts targets on maps
 */
public class MyItemizedOverlay extends ItemizedOverlay {
	private ArrayList<MyOverlayItem> mOverlays = new ArrayList<MyOverlayItem>();
	private Context mContext;
	private MapView mMapView;

	private class MyProgress extends
			AsyncTask<Integer, Integer, List<MyAddress>> {

		private ProgressDialog dialog;
		private MyOverlayItem item;
		private String address;
		private AddressFoundCallback addressFoundCallback = new AddressFoundCallback() {
			private int found = 0;

			@Override
			public void addressFound(int i) {
				publishProgress(i);
			}
		};
		
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			dialog = ProgressDialog.show(mContext,
					"Looking up approximate address", "contacting google ...");
			dialog.show();
		}

		/*
		 * Runs in UI
		 * 
		 * @see android.os.AsyncTask#onProgressUpdate(Progress[])
		 */
		@Override
		protected void onProgressUpdate(Integer... values) {
			dialog.setMessage("found "
					+ values[0]
					+ (values[0] == 1 ? " address"
							: " addresses (only using first)"));
		}

		@Override
		protected List<MyAddress> doInBackground(Integer... params) {
			item = mOverlays.get(params[0]);
			List<MyAddress> fromLocation = Collections.emptyList();
			try {
				fromLocation = new HttpGeoCoder().geocode((double) (item
						.getPoint().getLatitudeE6() / 1e6), (double) (item
						.getPoint().getLongitudeE6() / 1e6),
						addressFoundCallback, 1);
				address = fromLocation.size() == 0 ? "" : "\r\n"
						+ fromLocation.get(0).getFormattedAddress();
			} catch (IOException e) {
				e.printStackTrace();
			}
			// Get the coordinates of the overlay item so
			// the toast can be near it.
			catch (SAXException e) {
				e.printStackTrace();
			} catch (ParserConfigurationException e) {
				e.printStackTrace();
			}
			
			return fromLocation;
		}

		@Override
		protected void onPostExecute(List<MyAddress> result) {
			super.onPostExecute(result);
			dialog.setMessage("Done");
			try {
				// Let the user see "Done" for a little while
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			// Build toast
			StringBuffer sb = new StringBuffer();

			sb.append(new String(item.getTitle() + "\r\n" + item.getSnippet()
					+ " " + address));

			// Calculate distance to target
			if (!TargetUpdateReceiver.ME_URI.equals(item.mUri)) {
				GeoPoint targetPoint = item.getPoint();
				float[] results = new float[1];
				results[0] = -1;
				Location.distanceBetween(MyHelper.getLatitude(mContext),
						MyHelper.getLongitude(mContext), targetPoint
								.getLatitudeE6() / 1e6, targetPoint
								.getLongitudeE6() / 1e6, results);
				
				if (results[0] != -1) {
					int total = ((int) results[0]);
					StringBuffer sbm = formatDistance(total);
					sb.append(sbm);
				}
			}

			// Place toast
			Point screenPts = new Point();
			mMapView.getProjection().toPixels(item.getPoint(), screenPts);
			Toast toast = Toast.makeText(mContext, sb.toString(),
					Toast.LENGTH_SHORT);
			toast.setGravity(Gravity.LEFT | Gravity.TOP, screenPts.x,
					screenPts.y);

			// Remove the progress dialog at the latest possible moment
			dialog.dismiss();

			// Show toast
			toast.show();
		}

	}

	/**
	 * format human readable string from meters.  Public so it can be tested.
	 * @param total
	 * @return
	 */
	static public StringBuffer formatDistance(int total) {
		int kilometers = total / 1000;
		int meters = total % 1000;
		StringBuffer sbm = new StringBuffer(" ");
		
		switch (kilometers) {
		case 0:
			break;
		case 1:
			sbm.append(kilometers + " km ");
			break;
		default:
			sbm.append(kilometers + " km's ");
		}
		
		switch (meters) {
		case 0:
			break;
		case 1:
			sbm.append(meters + " m");
			break;
		default :
			sbm.append(meters + " m's");
		}
		
		return sbm;
	}

	private MyItemizedOverlay(Drawable defaultMarker) {
		super(boundCenterBottom(defaultMarker));
	}

	public MyItemizedOverlay(Context context, Drawable defaultMarker,
			MapView view) {
		super(boundCenterBottom(defaultMarker));
		mContext = context;
		mMapView = view;
	}

	public void addOverlay(MyOverlayItem overlay) {
		mOverlays.add(overlay);
		populate();
	}

	@Override
	protected boolean onTap(int index) {
		// Progress screen
		MyProgress myProgress = new MyProgress();
		myProgress.execute(new Integer(index));

		return true;
	}

	@Override
	protected OverlayItem createItem(int i) {
		return mOverlays.get(i);
	}

	@Override
	public int size() {
		return mOverlays.size();
	}

}
